<?php
/*
 * kernel/object.view.php 
 * 
 * This code is distributed and used under the GNU GPL v2 License,
 * please, read file LICENSE, which is situated in root directory,
 * or in "LICENSE" directory with most acceptable translation for you
 *
 * templates engine
 * 
 * Copyright (C) 2010, Taras Kudla
 * 
 */

class gView extends gKernel {

    /**
     *
     * @var <type>
     */
    private $url                = null;
    /**
     *
     * @var <type>
     */
    private $CurrentTplMod      = null;
    /**
     *
     * @var <type>
     */
    private $tempatesDirectory  = null;
    /**
     *
     * @var <type>
     */
    private $templatesUrl       = null;
    /**
     *
     * @var <type>
     */
    private $modsurl		= null;
    /**
     *
     * @var <type>
     */
    private $appmodsurl         = null;
    /**
     *
     * @var <type>
     */
    private $jscoreurl          = null;
    /**
     *
     * @var <type>
     */
    private $tplCache           = array();
    /**
     *
     * @var <type>
     */
    public $engine             = null;

    /**
     * Object initialization method
     *
     * @see abstract.layer.php
     * @return boolean
     */
    public function init (){
        $this->url                  = $this->core->url();
        $this->templatesDirectory   = $this->core->parseasdir($this->core->get("templatesdir"));
        $this->templatesUrl         = $this->core->parseasurl($this->core->get("templatesurl"));
        $this->modsurl              = $this->core->parseasurl($this->core->get("modsurl"));
        $this->appmodsurl           = $this->core->parseasurl($this->core->get("appmodsurl"));
        $this->jscoreurl            = $this->core->parseasurl($this->core->get("jscoreurl"));
        # setting up templates engine
        $engine     = $this->core->get("tplengine");
        $adapter = $this->getAdapter($engine);
        if( !$adapter ){
            $this->core->error("view","Cannot found system templates parsing engine '$engine'");
            return false;
        }
        $this->engine = $adapter;
        $this->engine->init();
        return true;
    }

    /**
     * Get url to modules path
     *
     * @return string
     */
    public function getmodsurl(){
        return $this->modsurl;
    }
    /**
     * Get url to 3-rd party modules path
     *
     * @return string
     */
    public function getappmodsurl(){
        return $this->appmodsurl;
    }
    /**
     * Get url to javascript core files
     *
     * @return string
     */
    public function getjscoreurl(){
        return $this->jscoreurl;
    }
    /**
     * Get path to view templates directory
     *
     * @return string
     */
    public function gettemplatesdir(){
        return $this->templatesDirectory;
    }

    /**
     * Get url to view templates directory
     *
     * @return string
     */
    public function gettemplatesurl(){
        return $this->templatesUrl;
    }

    /**
     * Alias to render()
     * 
     * @return string
     */
    public function getreadydata(){
    	return $this->render();
    }

    /**
     * Prepares global output template to return as a string of pre-filled output areas
     * 
     * @return string
     */
    public function render(){
       
        $modelname = $this->core->get("viewmodel");
        if ($this->core->get("runmode") == _CONSOLE_RUNMODE){
            print "ViewModels in console mode are disabled...\n";
            return false;
        }
        $link   = $this->templatesUrl.$modelname."/";
        $tfile  = $this->templatesDirectory.$modelname."/page.html";
        $templateData = $this->loadtemplatedata($tfile);
        $templateData = $this->engine->parser($templateData);
        # images, css, js files replacing
        $templateData = preg_replace("/<link([^>]+)href\s*=\s*(['\"])(?!http|https|\/|{sys url})([^\"']+)\\2([^>]*)>/is",
         "<link$1href=$2" . $link . "$3$2$4>", $templateData);
        $templateData = preg_replace("/<img([^>]+)src\s*=\s*(['\"])(?!http|https|{sys url}|\/)([^\"']+)\\2([^>]*)\>/isU",
         "<img$1src=$2" . $link . "$3$2$4>", $templateData);
        $templateData = preg_replace("/<script([^>]+)src\s*=\s*(['\"])(?!http|https|{sys url}|\/)([^\"']+)\\2([^>]*)\>/isU",
         "<script$1src=$2" . $link . "$3$2$4>", $templateData);
        # global output areas data inserting
        if( $this->core->isloaded("cms") ){
            $outvalues=$this->core->cms->getoutvalues();
            $outdata  =$this->core->cms->getoutdata();
            foreach ($outvalues as $key => &$data){
                asort($data,SORT_NUMERIC);
                $outputdata = null;
                foreach($data as $action=> &$value){
                    $outputdata .= $outdata[$action]["data"];
                }
            $templateData = preg_replace("/\{\s*\%output\s+".$key."\s*\}/i",$outputdata,$templateData);
            }
        }
        /*
         * parsing system title
         */
        if( $this->core->cms->htmltitle!=null){
            $templateData = preg_replace("/\<\s*title\s*\>(.+)\<\/\s*title\s*\>/isU","<title>".$this->core->cms->htmltitle."</title>",$templateData);
        }
        $this->core->debug("view","template '$modelname' loaded and data parsed");
        /*
        * prepare all http headers
        */
        $this->core->document->prepareheaders();
        return $templateData;
    }

    /**
     * Text (template) processing directly on templates engine (on prce,or native)
     *
     * @param string        $text       text to processing
     * @param array         $data       array of data (variables mostly)
     * @param gi18n_image   $language   language (i18n) object
     * @return string
     * @see gi18n
     *
     */
    public function parse( $text,$data = null, $language = null ){
        if( is_object($this->engine)){
            return $this->engine->parsetext($text,$data, $language);
        }
        return false;
    }

    /**
     * Helps to detect module template location and url according to module
     * path and configuration
     *
     * @param string $mod   module name
     * @param string $tpl   template name
     * @return array
     */
    public function detecttemplate($mod, $tpl){
        /*
         *  checking if system template required
         */
        if ($mod == "system"){
            $file = $this->core->path()."view/templates/".$this->core->get("viewmodel")."/_system_/" . $tpl;
            return file_exists($file) ? array($file,$this->url."view/templates/" .$this->core->get("viewmodel"). "/_system_/"):false;
        } else {
            $file = $this->templatesDirectory.$this->core->get("viewmodel"). "/_mod_/" . $mod . "/" . $tpl;
            if( $this->core->cms->checkappmod($mod)  ){
                $file2 = $this->core->parseasdir($this->core->get("appmodsdir")). $mod . "/tpl/" . $tpl;
            } else {
                $file2 = $this->core->parseasdir($this->core->get("modsdir")). $mod . "/tpl/" . $tpl;
            }
        }
        $modurl = $this->core->cms->checkappmod($mod)?$this->appmodsurl:$this->modsurl;
        if (file_exists($file)){
            return array($file,$this->url."view/templates/" .$this->core->get("viewmodel"). "/_mod_/" . $mod . "/");
        }
        if (file_exists($file2)){
            return array($file2,$modurl. $mod . "/tpl/");
        }
        return false;
    }

    /**
     * Alias to rendermodview
     * 
     * @param string    $tpl        template name
     * @param array     $vars       array of data
     * @param string    $mod        modulename
     * @param boolean   $parsephp   parse directly as a php file
     * @return string
     */
    public function template($tpl, $vars = null,$mod=null,$parsephp=false){
    	return $this->rendermodview($tpl, $vars ,$mod,$parsephp);
    }

    /**
     * Prepares module view template to return as a string
     *
     * @param string    $tpl        template name
     * @param array     $vars       array of data
     * @param string    $mod        modulename
     * @param boolean   $parsephp   parse directly as a php file
     * @return string
     */
    public function rendermodview($tpl, $vars = null,$mod=null,$parsephp=false){
        /*
         * 
         */
        if ($this->core->get("runmode") == _CONSOLE_RUNMODE){
            return false;
        }
        $startTime = microtime(1);
        $data = null;
        /*
         * if modname is empty, detecting it by global execution
         * enviroment
         */
        if( $mod == null && $this->core->Getenvlayer()==_ENV_MOD ){
            $env = $this->core->Getenvcaller();
            $mod = $env["MOD"];
        }
        $this->CurrentTplMod = $mod;
        $this->engine->CurrentTplMod = $mod;
        if( preg_match("/\.php$/",$tpl)){
            $useasphp = true;
        } else {
            $tpl.=".html";
            $useasphp = false;
        }
        # parsing template file path and url
        list($file, $url) = $this->detecttemplate($mod, $tpl);
        if ($file == null || $url == null){
            $this->core->error("VIEW", "Cannot found template for '" . $mod . "' - '" . $tpl . "'");
            return false;
        }
        # checking if template is a php file
        # linking template vars data
        $this->engine->setvars($vars);
        if( !$useasphp ){
            # checking if template was previously loaded
            if (isset($this->tplCache[$file])){
                $data = $this->tplCache[$file];
            } else {
                # loading template data
                $data = $this->loadtemplatedata($file);
            }
            # Parsing all data
            $data = $this->engine->parser($data);
        } else {
            ob_start();
            # preparing global environment
            $lang = $this->core->i18n->getlangobj($this->core->getenvcaller("mod"));
            # trying to disable kernel environment
            $tmpcore = $this->core;
            $this->core=null;
            # preparing for variables
            extract($vars, EXTR_REFS, "tpl_");
            #
            require_once($file);
            # redtoring kernel environment
            $this->core=$tmpcore;
            # unsetting variables
            unset($data);
            unset($lang);
            # output buffer data
            $data=ob_get_contents();
            ob_end_clean();
            # parsing data
            if($parsephp) {
                $data = $this->engine->parser($data);
            }
        }
        # checking if page title defined
        if( preg_match("/\<\s*title\s*\>(.+)\<\/\s*title\s*\>/isU",$data,$tmp)){
            $this->core->cms->htmltitle = $tmp[1];
        }
        # Images sources replacement
        $data = preg_replace("/<img([^>]+)src\s*=\s*(['\"])(?!http|https|{sys way}|{ME}|\/)([^\"']+)\\2([^>]*)>/isU", "<img$1src=$2".$url."$3$2$4>", $data);
        # Css files replacement
        $data = preg_replace("/<link([^>]+)href\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<link$1href=$2".$url."$3$2$4>", $data);
        $data = preg_replace("/<script([^>]+)src\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<script$1src=$2".$url."$3$2$4>", $data);
        # Replacing document.cookie,window.cookie
        $data = preg_replace(array("/document\.cookie/i","/window\.cookie/i"), array("'document-cookie'","'window-cookie'"), $data);
        # Simple way replacement
        $data = preg_replace("/{ME}/Us", $url, $data);
        /*
         *  NOTE: Forms actions will changed only if it's empty ( form is connected with current event).
         *  If you want to connect your form with other events please use defined expression.
         */
        if ($this->core->get("runmode") == _AJAX_RUNMODE){
            # Updating forms to general configuration
            # NOTE: Only if form action="" (empty)
            $data = preg_replace("/<form([^>]+)action\s*=\s*([\"']{2})([^>]*)>/is", "<form$1action=\"" . $this->core->getenvcaller("ID"). "\"$3>", $data);
            # Updating button for action
            $data = preg_replace("/<input([^>])type=([\"'])?(submit)\\2([^>]*)>/is", "<input$1type=$2Button$2 onClick=$2javascript:processForm(this.form);$2 $4>", $data);
        }
        # setting template data to null
        $this->GlobalData = null;
        $this->core->debug("view","template '$tpl' parsed");
        return $data;
    }

    /**
     *
     * @param <type> $template
     * @param array $var
     * @return <type> 
     */
    public function systemplate($template,$var=null){
        if(!is_array($var))$var=array();
            $file = $this->templatesDirectory.$this->core->get("viewmodel")."/_system_/".$template.".html";
        if( file_exists($file)){
            $data = $this->loadtemplatedata($file);
            if( $this->core->isloaded("lang")){
                $lang = &$this->core->i18n;
            } else {
                $lang = null;
            }
            $data = $this->parse($data,$var,$lang);
            $url  = $this->templatesUrl."".$this->core->get("viewmodel")."/_system_/";
            $data = preg_replace("/<img([^>]+)src\s*=\s*(['\"])(?!http|https|{sys way}|\/)([^\"']+)\\2([^>]*)>/isU", "<img$1src=$2" . $url . "$3$2$4>", $data);
            $data = preg_replace("/<link([^>]+)href\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<link$1href=$2" . $url . "$3$2$4>", $data);
            $data = preg_replace("/<script([^>]+)src\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<script$1src=$2" . $url . "$3$2$4>", $data);
            return $data;
        } else {
            $this->core->error("VIEW","System template '$template' no found");
            return false;
        }
        return true;
    }

    /**
     * Get view template text data, optimized vs caching engine
     *
     * @param string $filename full file path
     * @return string
     */
    public function & loadtemplatedata($filename){
        # Checking for caching engine
        if( $this->core->get("usecache") &&  $this->core->isloaded("cache")){
            # Checking if template is in memory alreay
            $name = "gepard.view.".md5($filename);
            $datename = $name.".date";
            $ctime = $this->core->cache->get($datename);
            if( $ctime ){
                $mtime = filemtime($filename);
                if( $mtime > $ctime){
                    #need to rebuild cache
                    $filedata=file_get_contents($filename);
                    $this->core->cache->set($datename,time());
                    $this->core->cache->set($name,$filedata);
                    $this->core->debug("view","rebuilding cache for template '' ");
                }else {
                    #returning data from cache
                    $filedata = $this->core->cache->get($name);
                    $this->core->debug("view","getting template from cache");
                }
            } else {
                # need to build cache
                $filedata=file_get_contents($filename);
                $this->core->cache->set($datename,time());
                $this->core->cache->set($name,$filedata);
                $this->core->debug("view","putting template data into cache");
            }
        } else {
            # anyway, returning back a text data
            $filedata=file_get_contents($filename);
        }
        return $filedata;
    }
}